% =============================================================================
% Automated modeling in process-based qualitative reasoning
%  ** Condition handling module - 	Contains predicates that make conditional
%									MFs for initial value assignments
% 
% April - July 2007
% 
% Hylke Buisman   - hbuisman@science.uva.nl
% =============================================================================

:- dynamic curr_partition/1.

%==============================================================================
% CONDITION HANDLING
%==============================================================================

% Place a value assignment on Q. Since such a value assignment is useless
% when the quantity on which the condition is place is unkown. Thus we will
% place a condition on some known value.
% conditional_value_assignment/3
% conditional_value_assignment(+UnknownQuantity, +KnownQuants, -ConditionalMF)
conditional_value_assignment(Q, Knowns, MFs) :-
	member(Q2/scenario, Knowns),
	findall(S, engine:state(S, _), States),
	get_condition_mapping(States, Q, Q2, Mapping),
	get_qs_partition(Q2, Partition),
	determine_condition(Mapping, Partition, Q, Q2, MFs).
	
	
% Determine which conditions should be placed
% Based on magnitudes, not on derivatives
% Fails if no consistent (unambiguous Q1 -> Q2) mapping can be found
% get_condition_mapping/4
% get_condition_mapping(+States, +Q1, +Q2, -Mapping)
get_condition_mapping([], _, _, []).
get_condition_mapping([S|T], Q1, Q2, MappingSet) :-
	get_quantity_values(S, magnitude, Q1, Value1),
	get_quantity_values(S, magnitude, Q2, Value2),
	get_condition_mapping(T, Q1, Q2, Mapping),
	(member(V/Value2, Mapping) 
	-> V = Value1
	; true),
	list_to_set([Value1/Value2|Mapping], MappingSet).
	
	
% Determine the condition that is consistent with the given mapping
% Converts the mapping into a conditional MF
% determine_condition/5
% determine_condition(+Mapping, +Q2QSParitition, +Q1, +Q2, -MFs)
determine_condition(Mapping, Partition, Q1, Q2, MFs) :-
	retractall(curr_partition(_)),
	assert(curr_partition(Partition)),
	predsort(compare_maps, Mapping, Sorted),
	merge_intervals(Sorted, Intervals),
	intervals_to_MFs(Intervals, Q1, Q2, MFs).
	
	
% Convert intervals to conditional MFs with value assignments
% Makes a model fragment where the value of GoalQ is set
% by placing a condition on ConditionalQ, based on Intervals
% intervals_to_MFs/4
% intervals_to_MFs(+Intervals, +GoalQ, +ConditionalQ, -MFs)
intervals_to_MFs([], _, _, []).
intervals_to_MFs([GoalVal/[From, From]|T], GoalQ, ConditionalQ, 
		[mf(Conditions, Consequences)|MFs]) :-
	intervals_to_MFs(T, GoalQ, ConditionalQ, MFs),
	curr_partition(P),
	member(point(From), P),!,
	Conditions = [model_dependency(equal, [ConditionalQ, From])],
	Consequences = [value(GoalQ, _, GoalVal,_)].
intervals_to_MFs([GoalVal/[From, To]|T], GoalQ, ConditionalQ, 
		[mf(NConditions, Consequences)|MFs]) :-
	intervals_to_MFs(T, GoalQ, ConditionalQ, MFs),
	Conditions = [model_dependency(greater_or_equal, [ConditionalQ, From])],
	NConditions = [model_dependency(smaller_or_equal, [ConditionalQ, To])|Conditions],
	Consequences = [value(GoalQ, _, GoalVal,_)].
	
		
% Wrapper for merge_intervals/3
% merge_intervals/2
% merge_intervals(+Mapping, -Intervals)
merge_intervals([VAValue/ConditionalVal|T], Intervals) :-
	merge_intervals(T, [VAValue/[ConditionalVal, ConditionalVal]], Intervals).
	
% Merge intervals / points from the mapping that map to the same
% value for the unknown quantity.
% merge_intervals/3
merge_intervals([], Intervals, Intervals).
merge_intervals([VAValue/ConditionalVal|T], [VAValue/[From, _]|Rest], Out) :-
	!,
	merge_intervals(T, [VAValue/[From, ConditionalVal]|Rest], Out).
merge_intervals([VAValue/ConditionalVal|T], [VAValue2/[From, To]|Rest], Out) :-
	merge_intervals(T, [VAValue/[ConditionalVal, ConditionalVal],VAValue2/[From, To]|Rest], Out).
	
	
% Predicate to sort mappings. Used in combination with predsort/3 (built-in)
% to ensure that the mapping is the same order as the partition
% compare_maps/3
% compare_maps(-Delta, +Element1, +Element2)
compare_maps(>, _/V2, _/V4) :-
	curr_partition(P),
	(nth0(N1, P, V2);nth0(N1, P, point(V2))),
	(nth0(N2, P, V4);nth0(N2, P, point(V4))),
	N1 > N2.
compare_maps(<, _/V2, _/V4) :-
	curr_partition(P),
	(nth0(N1, P, V2);nth0(N1, P, point(V2))),
	(nth0(N2, P, V4);nth0(N2, P, point(V4))),
	N1 < N2.
compare_maps(=, _/V2, _/V4) :-
	curr_partition(P),
	(nth0(N1, P, V2);nth0(N1, P, point(V2))),
	(nth0(N2, P, V4);nth0(N2, P, point(V4))),
	N1 = N2.
	